package com.xiaohua.api.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONArray;
import com.xiaohua.api.common.enums.CertTypeEnums;
import com.xiaohua.api.common.constants.TextInConstants;
import com.xiaohua.api.utils.security.TextInCacheUtils;
import com.xiaohua.api.common.constants.TextInFieldMappings;
import com.xiaohua.api.common.properties.TextInProperties;
import com.xiaohua.api.service.IXhApiCredentialsService;
import com.xiaohua.api.service.IXhCertService;
import com.xiaohua.common.core.domain.AjaxResult;
import com.xiaohua.common.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.MessageDigest;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.ArrayList;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 证件识别Service实现
 * 
 * @author 小花
 * @date 2025-03-29
 */
@Service
public class XhCertServiceImpl implements IXhCertService {
    private static final Logger log = LoggerFactory.getLogger(XhCertServiceImpl.class);
    
    // 图片识别结果缓存，使用图片哈希值作为键，识别结果作为值
    private static final ConcurrentHashMap<String, TextInCacheUtils.CacheEntry> RECOGNITION_CACHE = new ConcurrentHashMap<>();
    
    @Autowired
    private IXhApiCredentialsService apiCredentialsService;
    
    @Autowired
    private TextInProperties textInProperties;
    
    /**
     * 证件分类识别
     */
    @Override
    public AjaxResult classifyCertificate(String imageBase64) {
        if (StringUtils.isEmpty(imageBase64)) {
            return AjaxResult.error("图片数据不能为空");
        }

        try {
            // 如果base64包含前缀，去除前缀
            String cleanBase64 = imageBase64;
            if (imageBase64.contains(",")) {
                cleanBase64 = imageBase64.substring(imageBase64.indexOf(",") + 1);
            }

            log.info("使用Base64进行证件分类识别，数据长度: " + cleanBase64.length() + " 字符");

            // 检查文件大小限制（粗略估计）
            if (cleanBase64.length() > 13 * 1024 * 1024) { // ~10MB的base64大约13MB字符
                log.error("Base64数据大小超过限制，当前长度: " + cleanBase64.length() + " 字符");
                return AjaxResult.error("文件大小超过限制（最大10MB）");
            }

            // 将Base64解码为二进制数据
            byte[] imageBytes = Base64.getDecoder().decode(cleanBase64);

            // 调用API进行识别 - 使用二进制流模式
            String result = requestTextinApi(imageBytes, false, TextInConstants.API_URL_CERT_CLASSIFY);

            // 解析结果
            return parseClassifyResult(result);
        } catch (Exception e) {
            log.error("证件分类识别出错", e);
            return AjaxResult.error("证件分类识别出错: " + e.getMessage());
        }
    }
    
    /**
     * 根据URL进行证件分类识别
     */
    @Override
    public AjaxResult classifyCertificateByUrl(String imageUrl) {
        if (StringUtils.isEmpty(imageUrl)) {
            return AjaxResult.error("图片URL不能为空");
        }

        try {
            log.info("使用URL进行证件分类识别: " + imageUrl);

            // 调用API进行识别 - 使用URL模式
            String result = requestTextinApiWithUrl(imageUrl, TextInConstants.API_URL_CERT_CLASSIFY);

            // 解析结果
            return parseClassifyResult(result);
        } catch (Exception e) {
            log.error("证件分类识别出错", e);
            return AjaxResult.error("证件分类识别出错: " + e.getMessage());
        }
    }

    /**
     * 解析证件分类结果
     */
    private AjaxResult parseClassifyResult(String jsonResult) {
        try {
            JSONObject resultObj = JSON.parseObject(jsonResult);

            // 检查响应码
            if (!resultObj.containsKey("code") || resultObj.getIntValue("code") != 200) {
                String message = resultObj.getString("message");
                return AjaxResult.error("证件分类识别失败: " + message);
            }

            // 获取结果数据
            JSONObject data = resultObj.getJSONObject("result");
            if (data == null) {
                return AjaxResult.error("证件分类识别结果为空");
            }

            String type = data.getString("type");
            
            // 创建返回数据
            Map<String, Object> classifyInfo = new HashMap<>();
            classifyInfo.put("type", type);
            classifyInfo.put("typeDesc", CertTypeEnums.getDescriptionByCode(type));
            
            // 忽略不重要的元数据
            if (data.containsKey("confidence")) {
                classifyInfo.put("confidence", data.getDoubleValue("confidence"));
            }

            return AjaxResult.success("证件分类识别成功")
                    .put("classifyInfo", classifyInfo);
        } catch (Exception e) {
            log.error("解析证件分类结果出错", e);
            return AjaxResult.error("解析证件分类结果出错: " + e.getMessage());
        }
    }
    
    /**
     * 身份证识别
     */
    @Override
    public AjaxResult recognizeIdCard(String imageBase64) {
        if (StringUtils.isEmpty(imageBase64)) {
            return AjaxResult.error("图片数据不能为空");
        }

        try {
            // 如果base64包含前缀，去除前缀
            String cleanBase64 = imageBase64;
            if (imageBase64.contains(",")) {
                cleanBase64 = imageBase64.substring(imageBase64.indexOf(",") + 1);
            }

            log.info("使用Base64识别身份证，数据长度: " + cleanBase64.length() + " 字符");

            // 检查文件大小限制（粗略估计）
            if (cleanBase64.length() > 13 * 1024 * 1024) { // ~10MB的base64大约13MB字符
                log.error("Base64数据大小超过限制，当前长度: " + cleanBase64.length() + " 字符");
                return AjaxResult.error("文件大小超过限制（最大10MB）");
            }

            // 将Base64解码为二进制数据
            byte[] imageBytes = Base64.getDecoder().decode(cleanBase64);

            // 调用API进行识别 - 使用二进制流模式
            String result = requestTextinApi(imageBytes, false, TextInConstants.API_URL_RECOGNIZE_ID_CARD);

            // 解析结果并返回
            return parseIdCardResult(result);
        } catch (IllegalArgumentException e) {
            log.error("Base64解码失败", e);
            return AjaxResult.error("Base64解码失败: " + e.getMessage());
        } catch (Exception e) {
            log.error("身份证识别出错", e);
            return AjaxResult.error("身份证识别出错: " + e.getMessage());
        }
    }
    
    /**
     * 根据URL识别身份证
     */
    @Override
    public AjaxResult recognizeIdCardByUrl(String imageUrl) {
        if (StringUtils.isEmpty(imageUrl)) {
            return AjaxResult.error("图片URL不能为空");
        }

        try {
            log.info("使用URL识别身份证: " + imageUrl);

            // 调用API进行识别 - 使用URL模式
            String result = requestTextinApiWithUrl(imageUrl, TextInConstants.API_URL_RECOGNIZE_ID_CARD);

            // 解析结果并返回
            return parseIdCardResult(result);
        } catch (Exception e) {
            log.error("身份证识别出错", e);
            return AjaxResult.error("身份证识别出错: " + e.getMessage());
        }
    }

    /**
     * 解析身份证识别结果
     */
    private AjaxResult parseIdCardResult(String jsonResult) {
        // 使用通用方法解析结果，从TextInFieldMappings获取字段映射
        return parseApiResult(jsonResult, "身份证识别成功", "身份证识别失败", 
                              CertTypeEnums.ID_CARD.getInfoKey(), 
                              TextInFieldMappings.getIdCardFieldMappings());
    }
    
    /**
     * 营业执照识别
     */
    @Override
    public AjaxResult recognizeBusinessLicense(String imageBase64) {
        if (StringUtils.isEmpty(imageBase64)) {
            return AjaxResult.error("图片数据不能为空");
        }

        try {
            // 如果base64包含前缀，去除前缀
            String cleanBase64 = imageBase64;
            if (imageBase64.contains(",")) {
                cleanBase64 = imageBase64.substring(imageBase64.indexOf(",") + 1);
            }

            log.info("使用Base64识别营业执照，数据长度: " + cleanBase64.length() + " 字符");

            // 检查文件大小限制
            if (cleanBase64.length() > 13 * 1024 * 1024) {
                log.error("Base64数据大小超过限制，当前长度: " + cleanBase64.length() + " 字符");
                return AjaxResult.error("文件大小超过限制（最大10MB）");
            }

            // 将Base64解码为二进制数据
            byte[] imageBytes = Base64.getDecoder().decode(cleanBase64);

            // 调用API进行识别
            String result = requestTextinApi(imageBytes, false, TextInConstants.API_URL_RECOGNIZE_BUSINESS_LICENSE);

            // 解析结果
            return parseBusinessLicenseResult(result);
        } catch (Exception e) {
            log.error("营业执照识别出错", e);
            return AjaxResult.error("营业执照识别出错: " + e.getMessage());
        }
    }
    
    /**
     * 根据URL识别营业执照
     */
    @Override
    public AjaxResult recognizeBusinessLicenseByUrl(String imageUrl) {
        if (StringUtils.isEmpty(imageUrl)) {
            return AjaxResult.error("图片URL不能为空");
        }

        try {
            log.info("使用URL识别营业执照: " + imageUrl);

            // 调用API进行识别
            String result = requestTextinApiWithUrl(imageUrl, TextInConstants.API_URL_RECOGNIZE_BUSINESS_LICENSE);

            // 解析结果
            return parseBusinessLicenseResult(result);
        } catch (Exception e) {
            log.error("营业执照识别出错", e);
            return AjaxResult.error("营业执照识别出错: " + e.getMessage());
        }
    }

    /**
     * 解析营业执照识别结果
     */
    private AjaxResult parseBusinessLicenseResult(String jsonResult) {
        // 使用通用方法解析结果，从TextInFieldMappings获取字段映射
        return parseApiResult(jsonResult, "营业执照识别成功", "营业执照识别失败", 
                              CertTypeEnums.BUSINESS_LICENSE.getInfoKey(), 
                              TextInFieldMappings.getBusinessLicenseFieldMappings());
    }
    
    /**
     * 行驶证识别
     */
    @Override
    public AjaxResult recognizeVehicleLicense(String imageBase64) {
        if (StringUtils.isEmpty(imageBase64)) {
            return AjaxResult.error("图片数据不能为空");
        }

        try {
            // 如果base64包含前缀，去除前缀
            String cleanBase64 = imageBase64;
            if (imageBase64.contains(",")) {
                cleanBase64 = imageBase64.substring(imageBase64.indexOf(",") + 1);
            }

            log.info("使用Base64识别行驶证，数据长度: " + cleanBase64.length() + " 字符");

            // 检查文件大小限制
            if (cleanBase64.length() > 13 * 1024 * 1024) {
                log.error("Base64数据大小超过限制，当前长度: " + cleanBase64.length() + " 字符");
                return AjaxResult.error("文件大小超过限制（最大10MB）");
            }

            // 将Base64解码为二进制数据
            byte[] imageBytes = Base64.getDecoder().decode(cleanBase64);

            // 调用API进行识别
            String result = requestTextinApi(imageBytes, false, TextInConstants.API_URL_RECOGNIZE_VEHICLE_LICENSE);

            // 解析结果
            return parseVehicleLicenseResult(result);
        } catch (Exception e) {
            log.error("行驶证识别出错", e);
            return AjaxResult.error("行驶证识别出错: " + e.getMessage());
        }
    }
    
    /**
     * 根据URL识别行驶证
     */
    @Override
    public AjaxResult recognizeVehicleLicenseByUrl(String imageUrl) {
        if (StringUtils.isEmpty(imageUrl)) {
            return AjaxResult.error("图片URL不能为空");
        }

        try {
            log.info("使用URL识别行驶证: " + imageUrl);

            // 调用API进行识别
            String result = requestTextinApiWithUrl(imageUrl, TextInConstants.API_URL_RECOGNIZE_VEHICLE_LICENSE);

            // 解析结果
            return parseVehicleLicenseResult(result);
        } catch (Exception e) {
            log.error("行驶证识别出错", e);
            return AjaxResult.error("行驶证识别出错: " + e.getMessage());
        }
    }

    /**
     * 解析行驶证识别结果
     */
    private AjaxResult parseVehicleLicenseResult(String jsonResult) {
        // 使用通用方法解析结果，从TextInFieldMappings获取字段映射
        return parseApiResult(jsonResult, "行驶证识别成功", "行驶证识别失败", 
                              CertTypeEnums.VEHICLE_LICENSE.getInfoKey(), 
                              TextInFieldMappings.getVehicleLicenseFieldMappings());
    }
    
    /**
     * 驾驶证识别
     */
    @Override
    public AjaxResult recognizeDriverLicense(String imageBase64) {
        if (StringUtils.isEmpty(imageBase64)) {
            return AjaxResult.error("图片数据不能为空");
        }

        try {
            // 如果base64包含前缀，去除前缀
            String cleanBase64 = imageBase64;
            if (imageBase64.contains(",")) {
                cleanBase64 = imageBase64.substring(imageBase64.indexOf(",") + 1);
            }

            log.info("使用Base64识别驾驶证，数据长度: " + cleanBase64.length() + " 字符");

            // 检查文件大小限制
            if (cleanBase64.length() > 13 * 1024 * 1024) {
                log.error("Base64数据大小超过限制，当前长度: " + cleanBase64.length() + " 字符");
                return AjaxResult.error("文件大小超过限制（最大10MB）");
            }

            // 将Base64解码为二进制数据
            byte[] imageBytes = Base64.getDecoder().decode(cleanBase64);

            // 调用API进行识别
            String result = requestTextinApi(imageBytes, false, TextInConstants.API_URL_RECOGNIZE_DRIVER_LICENSE);

            // 解析结果
            return parseDriverLicenseResult(result);
        } catch (Exception e) {
            log.error("驾驶证识别出错", e);
            return AjaxResult.error("驾驶证识别出错: " + e.getMessage());
        }
    }
    
    /**
     * 根据URL识别驾驶证
     */
    @Override
    public AjaxResult recognizeDriverLicenseByUrl(String imageUrl) {
        if (StringUtils.isEmpty(imageUrl)) {
            return AjaxResult.error("图片URL不能为空");
        }

        try {
            log.info("使用URL识别驾驶证: " + imageUrl);

            // 调用API进行识别
            String result = requestTextinApiWithUrl(imageUrl, TextInConstants.API_URL_RECOGNIZE_DRIVER_LICENSE);

            // 解析结果
            return parseDriverLicenseResult(result);
        } catch (Exception e) {
            log.error("驾驶证识别出错", e);
            return AjaxResult.error("驾驶证识别出错: " + e.getMessage());
        }
    }

    /**
     * 解析驾驶证识别结果
     */
    private AjaxResult parseDriverLicenseResult(String jsonResult) {
        // 使用通用方法解析结果，从TextInFieldMappings获取字段映射
        return parseApiResult(jsonResult, "驾驶证识别成功", "驾驶证识别失败", 
                              CertTypeEnums.DRIVER_LICENSE.getInfoKey(), 
                              TextInFieldMappings.getDriverLicenseFieldMappings());
    }

    /**
     * 不重要的技术元数据字段，默认不包含在结果中
     */
    private static final Set<String> IGNORE_METADATA_FIELDS = new HashSet<String>() {{
        add("image_angle");
        add("rotated_image_width");
        add("rotated_image_height");
        add("type");
        add("type_description");
        add("imageAngle");
        add("imageWidth");
        add("imageHeight");
        add("confidence");
        add("position");
        add("rotation_degree");
        add("position_top_left_x");
        add("position_top_left_y");
        add("position_top_right_x");
        add("position_top_right_y");
        add("position_bottom_left_x");
        add("position_bottom_left_y");
        add("position_bottom_right_x");
        add("position_bottom_right_y");
    }};
    
    /**
     * 通用方法：对API返回结果进行解析并去重
     * 
     * @param jsonResult API返回的JSON结果
     * @param successMessage 成功消息
     * @param errorPrefix 错误前缀
     * @param infoKey 返回信息的键名
     * @param fieldMappings 字段映射（英文到中文）
     * @return 解析后的结果
     */
    private AjaxResult parseApiResult(String jsonResult, String successMessage, String errorPrefix, 
                                     String infoKey, Map<String, String> fieldMappings) {
        return parseApiResult(jsonResult, successMessage, errorPrefix, infoKey, fieldMappings, true);
    }
    
    /**
     * 通用方法：对API返回结果进行解析并去重
     * 
     * @param jsonResult API返回的JSON结果
     * @param successMessage 成功消息
     * @param errorPrefix 错误前缀
     * @param infoKey 返回信息的键名
     * @param fieldMappings 字段映射（英文到中文）
     * @param ignoreMetadata 是否忽略不重要的元数据字段
     * @return 解析后的结果
     */
    private AjaxResult parseApiResult(String jsonResult, String successMessage, String errorPrefix, 
                                     String infoKey, Map<String, String> fieldMappings, boolean ignoreMetadata) {
        try {
            // 添加调试日志，输出部分响应内容
            if (jsonResult != null && jsonResult.length() > 100) {
                log.info("API响应数据结构示例: {}", jsonResult.substring(0, Math.min(jsonResult.length(), 500)) + "...");
            }
            
            JSONObject resultObj = JSON.parseObject(jsonResult);
            
            // 检查响应码
            if (!resultObj.containsKey("code") || resultObj.getIntValue("code") != 200) {
                String message = resultObj.getString("message");
                return AjaxResult.error(errorPrefix + ": " + message);
            }
            
            // 获取结果数据
            JSONObject data = resultObj.getJSONObject("result");
            if (data == null) {
                return AjaxResult.error(errorPrefix + "结果为空");
            }
            
            // 创建返回数据，只使用中文字段名或简化的英文字段名
            Map<String, Object> infoMap = new HashMap<>();
            
            // 设置基本图像信息（如果不忽略元数据）
            if (!ignoreMetadata) {
                infoMap.put("证件类型", data.getString("type"));
                infoMap.put("图像角度", data.getIntValue("image_angle"));
                infoMap.put("图像宽度", data.getIntValue("rotated_image_width"));
                infoMap.put("图像高度", data.getIntValue("rotated_image_height"));
            }
            
            // 已处理的字段，避免重复
            Set<String> processedChineseKeys = new HashSet<>();
            
            // 解析item_list中的详细信息
            JSONArray itemList = data.getJSONArray("item_list");
            if (itemList != null) {
                log.info("发现item_list数组，包含{}个项目", itemList.size());
                if (itemList.size() > 0) {
                    log.info("第一个item示例: {}", itemList.getJSONObject(0).toString());
                }
                
                for (int i = 0; i < itemList.size(); i++) {
                    JSONObject item = itemList.getJSONObject(i);
                    String itemKey = item.getString("key");
                    
                    // 跳过null键
                    if (itemKey == null) {
                        log.warn("检测到null键，跳过此项: {}", item.toString());
                        continue;
                    }
                    
                    // 如果是需要被忽略的元数据字段，跳过
                    if (ignoreMetadata && TextInFieldMappings.IGNORE_METADATA_FIELDS.contains(itemKey)) {
                        continue;
                    }
                    
                    // 获取字段中文名称
                    String chineseKey = fieldMappings.getOrDefault(itemKey, itemKey);
                    
                    // 如果中文键与原始键相同，说明没有映射，记录下来
                    if (chineseKey.equals(itemKey)) {
                        log.info("发现未映射的字段: {}, 值: {}", itemKey, item.getString("value"));
                    }
                    
                    // 如果中文键为null，跳过
                    if (chineseKey == null) {
                        log.warn("字段[{}]映射后的中文键为null，跳过此项", itemKey);
                        continue;
                    }
                    
                    // 如果已处理过相同的中文键名，跳过
                    if (processedChineseKeys.contains(chineseKey)) {
                        continue;
                    }
                    
                    processedChineseKeys.add(chineseKey);
                    Object truncatedValue = TextInFieldMappings.truncateFieldValue(itemKey, item.getString("value"));
                    infoMap.put(chineseKey, truncatedValue);
                }
            }
            
            // 合并直接在result中的其他字段（如图像数据）
            for (Map.Entry<String, Object> entry : data.entrySet()) {
                String key = entry.getKey();
                
                // 跳过null键
                if (key == null) {
                    log.warn("检测到null键，跳过此项");
                    continue;
                }
                
                // 如果是需要被忽略的元数据字段，跳过
                if (ignoreMetadata && TextInFieldMappings.IGNORE_METADATA_FIELDS.contains(key)) {
                    continue;
                }
                
                // item_list已单独处理，跳过
                if ("item_list".equals(key)) {
                    continue;
                }
                
                // 获取字段中文名称
                String chineseKey = fieldMappings.getOrDefault(key, key);
                
                // 如果中文键与原始键相同，说明没有映射，记录下来
                if (chineseKey.equals(key)) {
                    log.info("发现未映射的字段: {}, 值: {}", key, entry.getValue());
                }
                
                // 如果中文键为null，跳过
                if (chineseKey == null) {
                    log.warn("字段[{}]映射后的中文键为null，跳过此项", key);
                    continue;
                }
                
                // 如果已处理过相同的中文键名，跳过
                if (processedChineseKeys.contains(chineseKey)) {
                    continue;
                }
                
                processedChineseKeys.add(chineseKey);
                Object originalValue = entry.getValue();
                Object truncatedValue = TextInFieldMappings.truncateFieldValue(key, originalValue);
                infoMap.put(chineseKey, truncatedValue);
            }
            
            return AjaxResult.success(successMessage)
                    .put(infoKey, infoMap);
        } catch (Exception e) {
            log.error("解析识别结果出错", e);
            return AjaxResult.error(errorPrefix + " 解析结果出错: " + e.getMessage());
        }
    }
    
    /**
     * 银行卡识别
     */
    @Override
    public AjaxResult recognizeBankCard(String imageBase64) {
        if (StringUtils.isEmpty(imageBase64)) {
            return AjaxResult.error("图片数据不能为空");
        }
        
        try {
            // 如果base64包含前缀，去除前缀
            String cleanBase64 = imageBase64;
            if (imageBase64.contains(",")) {
                cleanBase64 = imageBase64.substring(imageBase64.indexOf(",") + 1);
            }
            
            log.info("使用Base64识别银行卡，数据长度: " + cleanBase64.length() + " 字符");
            
            // 检查文件大小限制（粗略估计）
            if (cleanBase64.length() > 13 * 1024 * 1024) { // ~10MB的base64大约13MB字符
                log.error("Base64数据大小超过限制，当前长度: " + cleanBase64.length() + " 字符");
                return AjaxResult.error("文件大小超过限制（最大10MB）");
            }
            
            // 将Base64解码为二进制数据
            byte[] imageBytes = Base64.getDecoder().decode(cleanBase64);
            
            // 调用API进行识别 - 使用二进制流模式
            String result = requestTextinApi(imageBytes, false, TextInConstants.API_URL_RECOGNIZE_BANK_CARD);
            
            // 解析响应结果并进行特定处理
            return parseBankCardResult(result);
        } catch (IllegalArgumentException e) {
            log.error("Base64解码失败", e);
            return AjaxResult.error("Base64解码失败: " + e.getMessage());
        } catch (Exception e) {
            log.error("银行卡识别出错", e);
            return AjaxResult.error("银行卡识别出错: " + e.getMessage());
        }
    }
    
    /**
     * 根据URL识别银行卡
     */
    @Override
    public AjaxResult recognizeBankCardByUrl(String imageUrl) {
        if (StringUtils.isEmpty(imageUrl)) {
            return AjaxResult.error("图片URL不能为空");
        }
        
        try {
            log.info("使用URL识别银行卡: " + imageUrl);
            
            // 调用API进行识别 - 使用URL模式
            String result = requestTextinApiWithUrl(imageUrl, TextInConstants.API_URL_RECOGNIZE_BANK_CARD);
            
            // 解析响应结果并进行特定处理
            return parseBankCardResult(result);
        } catch (Exception e) {
            log.error("银行卡识别出错", e);
            return AjaxResult.error("银行卡识别出错: " + e.getMessage());
        }
    }
    
    /**
     * 解析银行卡识别结果
     */
    private AjaxResult parseBankCardResult(String jsonResult) {
        // 使用通用方法解析结果，从TextInFieldMappings获取字段映射
        return parseApiResult(jsonResult, "银行卡识别成功", "银行卡识别失败", 
                              CertTypeEnums.BANK_CARD.getInfoKey(), 
                              TextInFieldMappings.getBankCardFieldMappings());
    }

    /**
     * 护照识别
     */
    @Override
    public AjaxResult recognizePassport(String imageBase64) {
        if (StringUtils.isEmpty(imageBase64)) {
            return AjaxResult.error("图片数据不能为空");
        }

        try {
            // 如果base64包含前缀，去除前缀
            String cleanBase64 = imageBase64;
            if (imageBase64.contains(",")) {
                cleanBase64 = imageBase64.substring(imageBase64.indexOf(",") + 1);
            }

            log.info("使用Base64识别护照，数据长度: " + cleanBase64.length() + " 字符");

            // 检查文件大小限制
            if (cleanBase64.length() > 13 * 1024 * 1024) {
                log.error("Base64数据大小超过限制，当前长度: " + cleanBase64.length() + " 字符");
                return AjaxResult.error("文件大小超过限制（最大10MB）");
            }

            // 将Base64解码为二进制数据
            byte[] imageBytes = Base64.getDecoder().decode(cleanBase64);

            // 调用API进行识别
            String result = requestTextinApi(imageBytes, false, TextInConstants.API_URL_RECOGNIZE_PASSPORT);

            // 解析结果
            return parsePassportResult(result);
        } catch (Exception e) {
            log.error("护照识别出错", e);
            return AjaxResult.error("护照识别出错: " + e.getMessage());
        }
    }

    /**
     * 根据URL识别护照
     */
    @Override
    public AjaxResult recognizePassportByUrl(String imageUrl) {
        if (StringUtils.isEmpty(imageUrl)) {
            return AjaxResult.error("图片URL不能为空");
        }

        try {
            log.info("使用URL识别护照: " + imageUrl);

            // 调用API进行识别
            String result = requestTextinApiWithUrl(imageUrl, TextInConstants.API_URL_RECOGNIZE_PASSPORT);

            // 解析结果
            return parsePassportResult(result);
        } catch (Exception e) {
            log.error("护照识别出错", e);
            return AjaxResult.error("护照识别出错: " + e.getMessage());
        }
    }

    /**
     * 解析护照识别结果
     */
    private AjaxResult parsePassportResult(String jsonResult) {
        // 使用通用方法解析结果，从TextInFieldMappings获取字段映射
        return parseApiResult(jsonResult, "护照识别成功", "护照识别失败", 
                              CertTypeEnums.PASSPORT.getInfoKey(), 
                              TextInFieldMappings.getPassportFieldMappings());
    }

    /**
     * 社保卡识别
     */
    @Override
    public AjaxResult recognizeSocialSecurityCard(String imageBase64) {
        if (StringUtils.isEmpty(imageBase64)) {
            return AjaxResult.error("图片数据不能为空");
        }

        try {
            // 如果base64包含前缀，去除前缀
            String cleanBase64 = imageBase64;
            if (imageBase64.contains(",")) {
                cleanBase64 = imageBase64.substring(imageBase64.indexOf(",") + 1);
            }

            log.info("使用Base64识别社保卡，数据长度: " + cleanBase64.length() + " 字符");

            // 检查文件大小限制
            if (cleanBase64.length() > 13 * 1024 * 1024) {
                log.error("Base64数据大小超过限制，当前长度: " + cleanBase64.length() + " 字符");
                return AjaxResult.error("文件大小超过限制（最大10MB）");
            }

            // 将Base64解码为二进制数据
            byte[] imageBytes = Base64.getDecoder().decode(cleanBase64);

            // 调用API进行识别
            String result = requestTextinApi(imageBytes, false, TextInConstants.API_URL_RECOGNIZE_SOCIAL_SECURITY_CARD);

            // 解析结果
            return parseSocialSecurityCardResult(result);
        } catch (Exception e) {
            log.error("社保卡识别出错", e);
            return AjaxResult.error("社保卡识别出错: " + e.getMessage());
        }
    }
    
    /**
     * 根据URL识别社保卡
     */
    @Override
    public AjaxResult recognizeSocialSecurityCardByUrl(String imageUrl) {
        if (StringUtils.isEmpty(imageUrl)) {
            return AjaxResult.error("图片URL不能为空");
        }

        try {
            log.info("使用URL识别社保卡: " + imageUrl);

            // 调用API进行识别
            String result = requestTextinApiWithUrl(imageUrl, TextInConstants.API_URL_RECOGNIZE_SOCIAL_SECURITY_CARD);

            // 解析结果
            return parseSocialSecurityCardResult(result);
        } catch (Exception e) {
            log.error("社保卡识别出错", e);
            return AjaxResult.error("社保卡识别出错: " + e.getMessage());
        }
    }

    /**
     * 解析社保卡识别结果
     */
    private AjaxResult parseSocialSecurityCardResult(String jsonResult) {
        // 使用通用方法解析结果，从TextInFieldMappings获取字段映射
        return parseApiResult(jsonResult, "社保卡识别成功", "社保卡识别失败", 
                              CertTypeEnums.SOCIAL_SECURITY_CARD.getInfoKey(), 
                              TextInFieldMappings.getSocialSecurityCardFieldMappings());
    }
    
    /**
     * 户口本识别
     */
    @Override
    public AjaxResult recognizeHouseholdRegister(String imageBase64) {
        if (StringUtils.isEmpty(imageBase64)) {
            return AjaxResult.error("图片数据不能为空");
        }

        try {
            // 如果base64包含前缀，去除前缀
            String cleanBase64 = imageBase64;
            if (imageBase64.contains(",")) {
                cleanBase64 = imageBase64.substring(imageBase64.indexOf(",") + 1);
            }

            log.info("使用Base64识别户口本，数据长度: " + cleanBase64.length() + " 字符");

            // 检查文件大小限制
            if (cleanBase64.length() > 13 * 1024 * 1024) {
                log.error("Base64数据大小超过限制，当前长度: " + cleanBase64.length() + " 字符");
                return AjaxResult.error("文件大小超过限制（最大10MB）");
            }

            // 将Base64解码为二进制数据
            byte[] imageBytes = Base64.getDecoder().decode(cleanBase64);

            // 调用API进行识别
            String result = requestTextinApi(imageBytes, false, TextInConstants.API_URL_RECOGNIZE_HOUSEHOLD_REGISTER);

            // 解析结果
            return parseHouseholdRegisterResult(result);
        } catch (Exception e) {
            log.error("户口本识别出错", e);
            return AjaxResult.error("户口本识别出错: " + e.getMessage());
        }
    }
    
    /**
     * 根据URL识别户口本
     */
    @Override
    public AjaxResult recognizeHouseholdRegisterByUrl(String imageUrl) {
        if (StringUtils.isEmpty(imageUrl)) {
            return AjaxResult.error("图片URL不能为空");
        }

        try {
            log.info("使用URL识别户口本: " + imageUrl);

            // 调用API进行识别
            String result = requestTextinApiWithUrl(imageUrl, TextInConstants.API_URL_RECOGNIZE_HOUSEHOLD_REGISTER);

            // 解析结果
            return parseHouseholdRegisterResult(result);
        } catch (Exception e) {
            log.error("户口本识别出错", e);
            return AjaxResult.error("户口本识别出错: " + e.getMessage());
        }
    }

    /**
     * 解析户口本识别结果
     */
    private AjaxResult parseHouseholdRegisterResult(String jsonResult) {
        // 使用通用方法解析结果，从TextInFieldMappings获取字段映射
        return parseApiResult(jsonResult, "户口本识别成功", "户口本识别失败", 
                              CertTypeEnums.HOUSEHOLD_REGISTER.getInfoKey(), 
                              TextInFieldMappings.getHouseholdRegisterFieldMappings());
    }
    
    /**
     * 使用二进制数据识别结婚证
     */
    @Override
    public AjaxResult recognizeMarriageCertificateWithBytes(byte[] imageBytes) {
        if (imageBytes == null || imageBytes.length == 0) {
            return AjaxResult.error("图片数据不能为空");
        }
        
        // 检查文件大小限制
        if (imageBytes.length > 10 * 1024 * 1024) { // 10MB
            log.error("图片大小超过限制，当前大小: " + imageBytes.length + " 字节");
            return AjaxResult.error("文件大小超过限制（最大10MB）");
        }
        
        try {
            log.info("使用二进制数据识别结婚证，数据大小: " + imageBytes.length + " 字节");
            
            // 直接使用二进制数据调用API
            String result = requestTextinApi(imageBytes, false, TextInConstants.API_URL_RECOGNIZE_MARRIAGE_CERTIFICATE);
            
            // 解析结果
            return parseMarriageCertificateResult(result);
        } catch (Exception e) {
            log.error("结婚证识别出错", e);
            return AjaxResult.error("结婚证识别出错: " + e.getMessage());
        }
    }
    
    /**
     * 结婚证识别
     */
    @Override
    public AjaxResult recognizeMarriageCertificate(String imageBase64) {
        if (StringUtils.isEmpty(imageBase64)) {
            return AjaxResult.error("图片数据不能为空");
        }
        
        try {
            // 如果base64包含前缀，去除前缀
            String cleanBase64 = imageBase64;
            if (imageBase64.contains(",")) {
                cleanBase64 = imageBase64.substring(imageBase64.indexOf(",") + 1);
            }
            
            log.info("使用Base64识别结婚证，数据长度: " + cleanBase64.length() + " 字符");
            
            // 检查文件大小限制
            if (cleanBase64.length() > 13 * 1024 * 1024) {
                log.error("Base64数据大小超过限制，当前长度: " + cleanBase64.length() + " 字符");
                return AjaxResult.error("文件大小超过限制（最大10MB）");
            }
            
            // 将Base64解码为二进制数据
            byte[] imageBytes = Base64.getDecoder().decode(cleanBase64);
            
            // 调用API进行识别
            String result = requestTextinApi(imageBytes, false, TextInConstants.API_URL_RECOGNIZE_MARRIAGE_CERTIFICATE);
            
            // 解析结果
            return parseMarriageCertificateResult(result);
        } catch (Exception e) {
            log.error("结婚证识别出错", e);
            return AjaxResult.error("结婚证识别出错: " + e.getMessage());
        }
    }
    
    /**
     * 根据URL识别结婚证
     */
    @Override
    public AjaxResult recognizeMarriageCertificateByUrl(String imageUrl) {
        if (StringUtils.isEmpty(imageUrl)) {
            return AjaxResult.error("图片URL不能为空");
        }
        
        try {
            log.info("使用URL识别结婚证: " + imageUrl);
            
            // 调用API进行识别
            String result = requestTextinApiWithUrl(imageUrl, TextInConstants.API_URL_RECOGNIZE_MARRIAGE_CERTIFICATE);
            
            // 解析结果
            return parseMarriageCertificateResult(result);
        } catch (Exception e) {
            log.error("结婚证识别出错", e);
            return AjaxResult.error("结婚证识别出错: " + e.getMessage());
        }
    }

    /**
     * 解析结婚证识别结果
     */
    private AjaxResult parseMarriageCertificateResult(String jsonResult) {
        // 使用通用方法解析结果，从TextInFieldMappings获取字段映射
        return parseApiResult(jsonResult, "结婚证识别成功", "结婚证识别失败", 
                              CertTypeEnums.MARRIAGE_CERTIFICATE.getInfoKey(), 
                              TextInFieldMappings.getMarriageCertificateFieldMappings());
    }
    
    /**
     * 房产证识别
     */
    @Override
    public AjaxResult recognizePropertyCertificate(String imageBase64) {
        if (StringUtils.isEmpty(imageBase64)) {
            return AjaxResult.error("图片数据不能为空");
        }

        try {
            // 如果base64包含前缀，去除前缀
            String cleanBase64 = imageBase64;
            if (imageBase64.contains(",")) {
                cleanBase64 = imageBase64.substring(imageBase64.indexOf(",") + 1);
            }

            log.info("使用Base64识别房产证，数据长度: " + cleanBase64.length() + " 字符");

            // 检查文件大小限制
            if (cleanBase64.length() > 13 * 1024 * 1024) {
                log.error("Base64数据大小超过限制，当前长度: " + cleanBase64.length() + " 字符");
                return AjaxResult.error("文件大小超过限制（最大10MB）");
            }

            // 将Base64解码为二进制数据
            byte[] imageBytes = Base64.getDecoder().decode(cleanBase64);

            // 调用API进行识别
            String result = requestTextinApi(imageBytes, false, TextInConstants.API_URL_RECOGNIZE_PROPERTY_CERTIFICATE);

            // 解析结果
            return parsePropertyCertificateResult(result);
        } catch (Exception e) {
            log.error("房产证识别出错", e);
            return AjaxResult.error("房产证识别出错: " + e.getMessage());
        }
    }
    
    /**
     * 根据URL识别房产证
     */
    @Override
    public AjaxResult recognizePropertyCertificateByUrl(String imageUrl) {
        if (StringUtils.isEmpty(imageUrl)) {
            return AjaxResult.error("图片URL不能为空");
        }

        try {
            log.info("使用URL识别房产证: " + imageUrl);

            // 调用API进行识别
            String result = requestTextinApiWithUrl(imageUrl, TextInConstants.API_URL_RECOGNIZE_PROPERTY_CERTIFICATE);

            // 解析结果
            return parsePropertyCertificateResult(result);
        } catch (Exception e) {
            log.error("房产证识别出错", e);
            return AjaxResult.error("房产证识别出错: " + e.getMessage());
        }
    }

    /**
     * 解析房产证识别结果
     */
    private AjaxResult parsePropertyCertificateResult(String jsonResult) {
        // 使用通用方法解析结果，从TextInFieldMappings获取字段映射
        return parseApiResult(jsonResult, "房产证识别成功", "房产证识别失败", 
                              CertTypeEnums.PROPERTY_CERTIFICATE.getInfoKey(), 
                              TextInFieldMappings.getPropertyCertificateFieldMappings());
    }
    
    /**
     * 出生证明识别
     */
    @Override
    public AjaxResult recognizeBirthCertificate(String imageBase64) {
        if (StringUtils.isEmpty(imageBase64)) {
            return AjaxResult.error("图片数据不能为空");
        }

        try {
            // 如果base64包含前缀，去除前缀
            String cleanBase64 = imageBase64;
            if (imageBase64.contains(",")) {
                cleanBase64 = imageBase64.substring(imageBase64.indexOf(",") + 1);
            }

            log.info("使用Base64识别出生证明，数据长度: " + cleanBase64.length() + " 字符");

            // 检查文件大小限制
            if (cleanBase64.length() > 13 * 1024 * 1024) {
                log.error("Base64数据大小超过限制，当前长度: " + cleanBase64.length() + " 字符");
                return AjaxResult.error("文件大小超过限制（最大10MB）");
            }

            // 将Base64解码为二进制数据
            byte[] imageBytes = Base64.getDecoder().decode(cleanBase64);

            // 调用API进行识别
            String result = requestTextinApi(imageBytes, false, TextInConstants.API_URL_RECOGNIZE_BIRTH_CERTIFICATE);

            // 解析结果
            return parseBirthCertificateResult(result);
        } catch (Exception e) {
            log.error("出生证明识别出错", e);
            return AjaxResult.error("出生证明识别出错: " + e.getMessage());
        }
    }
    
    /**
     * 根据URL识别出生证明
     */
    @Override
    public AjaxResult recognizeBirthCertificateByUrl(String imageUrl) {
        if (StringUtils.isEmpty(imageUrl)) {
            return AjaxResult.error("图片URL不能为空");
        }

        try {
            log.info("使用URL识别出生证明: " + imageUrl);

            // 调用API进行识别
            String result = requestTextinApiWithUrl(imageUrl, TextInConstants.API_URL_RECOGNIZE_BIRTH_CERTIFICATE);

            // 解析结果
            return parseBirthCertificateResult(result);
        } catch (Exception e) {
            log.error("出生证明识别出错", e);
            return AjaxResult.error("出生证明识别出错: " + e.getMessage());
        }
    }

    /**
     * 解析出生证明识别结果
     */
    private AjaxResult parseBirthCertificateResult(String jsonResult) {
        // 使用通用方法解析结果，从TextInFieldMappings获取字段映射
        return parseApiResult(jsonResult, "出生证明识别成功", "出生证明识别失败", 
                              CertTypeEnums.BIRTH_CERTIFICATE.getInfoKey(), 
                              TextInFieldMappings.getBirthCertificateFieldMappings());
    }
    
    /**
     * 学位证识别
     */
    @Override
    public AjaxResult recognizeDegreeCertificate(String imageBase64) {
        if (StringUtils.isEmpty(imageBase64)) {
            return AjaxResult.error("图片数据不能为空");
        }

        try {
            // 如果base64包含前缀，去除前缀
            String cleanBase64 = imageBase64;
            if (imageBase64.contains(",")) {
                cleanBase64 = imageBase64.substring(imageBase64.indexOf(",") + 1);
            }

            log.info("使用Base64识别学位证，数据长度: " + cleanBase64.length() + " 字符");

            // 检查文件大小限制
            if (cleanBase64.length() > 13 * 1024 * 1024) {
                log.error("Base64数据大小超过限制，当前长度: " + cleanBase64.length() + " 字符");
                return AjaxResult.error("文件大小超过限制（最大10MB）");
            }

            // 将Base64解码为二进制数据
            byte[] imageBytes = Base64.getDecoder().decode(cleanBase64);

            // 调用API进行识别
            String result = requestTextinApi(imageBytes, false, TextInConstants.API_URL_RECOGNIZE_DEGREE_CERTIFICATE);

            // 解析结果
            return parseDegreeCertificateResult(result);
        } catch (Exception e) {
            log.error("学位证识别出错", e);
            return AjaxResult.error("学位证识别出错: " + e.getMessage());
        }
    }
    
    /**
     * 根据URL识别学位证
     */
    @Override
    public AjaxResult recognizeDegreeCertificateByUrl(String imageUrl) {
        if (StringUtils.isEmpty(imageUrl)) {
            return AjaxResult.error("图片URL不能为空");
        }

        try {
            log.info("使用URL识别学位证: " + imageUrl);

            // 调用API进行识别
            String result = requestTextinApiWithUrl(imageUrl, TextInConstants.API_URL_RECOGNIZE_DEGREE_CERTIFICATE);

            // 解析结果
            return parseDegreeCertificateResult(result);
        } catch (Exception e) {
            log.error("学位证识别出错", e);
            return AjaxResult.error("学位证识别出错: " + e.getMessage());
        }
    }

    /**
     * 解析学位证识别结果
     */
    private AjaxResult parseDegreeCertificateResult(String jsonResult) {
        // 使用通用方法解析结果，从TextInFieldMappings获取字段映射
        return parseApiResult(jsonResult, "学位证识别成功", "学位证识别失败", 
                              CertTypeEnums.DEGREE_CERTIFICATE.getInfoKey(), 
                              TextInFieldMappings.getDegreeCertificateFieldMappings());
    }
    
    /**
     * 毕业证识别
     */
    @Override
    public AjaxResult recognizeGraduationCertificate(String imageBase64) {
        if (StringUtils.isEmpty(imageBase64)) {
            return AjaxResult.error("图片数据不能为空");
        }

        try {
            // 如果base64包含前缀，去除前缀
            String cleanBase64 = imageBase64;
            if (imageBase64.contains(",")) {
                cleanBase64 = imageBase64.substring(imageBase64.indexOf(",") + 1);
            }

            log.info("使用Base64识别毕业证，数据长度: " + cleanBase64.length() + " 字符");

            // 检查文件大小限制
            if (cleanBase64.length() > 13 * 1024 * 1024) {
                log.error("Base64数据大小超过限制，当前长度: " + cleanBase64.length() + " 字符");
                return AjaxResult.error("文件大小超过限制（最大10MB）");
            }

            // 将Base64解码为二进制数据
            byte[] imageBytes = Base64.getDecoder().decode(cleanBase64);

            // 调用API进行识别
            String result = requestTextinApi(imageBytes, false, TextInConstants.API_URL_RECOGNIZE_GRADUATION_CERTIFICATE);

            // 解析结果
            return parseGraduationCertificateResult(result);
        } catch (Exception e) {
            log.error("毕业证识别出错", e);
            return AjaxResult.error("毕业证识别出错: " + e.getMessage());
        }
    }
    
    /**
     * 根据URL识别毕业证
     */
    @Override
    public AjaxResult recognizeGraduationCertificateByUrl(String imageUrl) {
        if (StringUtils.isEmpty(imageUrl)) {
            return AjaxResult.error("图片URL不能为空");
        }

        try {
            log.info("使用URL识别毕业证: " + imageUrl);

            // 调用API进行识别
            String result = requestTextinApiWithUrl(imageUrl, TextInConstants.API_URL_RECOGNIZE_GRADUATION_CERTIFICATE);

            // 解析结果
            return parseGraduationCertificateResult(result);
        } catch (Exception e) {
            log.error("毕业证识别出错", e);
            return AjaxResult.error("毕业证识别出错: " + e.getMessage());
        }
    }

    /**
     * 解析毕业证识别结果
     */
    private AjaxResult parseGraduationCertificateResult(String jsonResult) {
        // 使用通用方法解析结果，从TextInFieldMappings获取字段映射
        return parseApiResult(jsonResult, "毕业证识别成功", "毕业证识别失败", 
                              CertTypeEnums.GRADUATION_CERTIFICATE.getInfoKey(), 
                              TextInFieldMappings.getGraduationCertificateFieldMappings());
    }
    
    /**
     * 统一证件识别
     */
    @Override
    public AjaxResult recognizeCertificate(String imageBase64, String certType) {
        // 检查参数
        if (StringUtils.isEmpty(imageBase64)) {
            return AjaxResult.error("图片数据不能为空");
        }
        
        if (StringUtils.isEmpty(certType)) {
            // 如果未指定证件类型，则默认为身份证
            certType = "id_card";
        }

        // 先记录调用信息
        log.info("调用统一证件识别接口，证件类型: {}", certType);
        
        // 根据证件类型调用不同的识别方法
        switch (certType) {
            case "id_card":
                return recognizeIdCard(imageBase64);
            case "bank_card":
                return recognizeBankCard(imageBase64);
            case "business_license":
                return recognizeBusinessLicense(imageBase64);
            case "vehicle_license":
                return recognizeVehicleLicense(imageBase64);
            case "driver_license":
                return recognizeDriverLicense(imageBase64);
            case "passport":
                return recognizePassport(imageBase64);
            case "social_security_card":
                return recognizeSocialSecurityCard(imageBase64);
            case "household_register":
                return recognizeHouseholdRegister(imageBase64);
            case "marriage_certificate":
                return recognizeMarriageCertificate(imageBase64);
            case "property_certificate":
                return recognizePropertyCertificate(imageBase64);
            case "birth_certificate":
                return recognizeBirthCertificate(imageBase64);
            case "degree_certificate":
                return recognizeDegreeCertificate(imageBase64);
            case "graduation_certificate":
                return recognizeGraduationCertificate(imageBase64);
            default:
                // 未知证件类型，返回错误
                return AjaxResult.error("不支持的证件类型: " + certType);
        }
    }
    
    /**
     * 根据URL统一识别证件
     */
    @Override
    public AjaxResult recognizeCertificateByUrl(String imageUrl, String certType) {
        // 检查参数
        if (StringUtils.isEmpty(imageUrl)) {
            return AjaxResult.error("图片URL不能为空");
        }
        
        if (StringUtils.isEmpty(certType)) {
            // 如果未指定证件类型，则默认为身份证
            certType = "id_card";
        }
        
        // 根据证件类型调用不同的识别方法
        switch (certType) {
            case "id_card":
                return recognizeIdCardByUrl(imageUrl);
            case "bank_card":
                return recognizeBankCardByUrl(imageUrl);
            case "business_license":
                return recognizeBusinessLicenseByUrl(imageUrl);
            case "vehicle_license":
                return recognizeVehicleLicenseByUrl(imageUrl);
            case "driver_license":
                return recognizeDriverLicenseByUrl(imageUrl);
            case "passport":
                return recognizePassportByUrl(imageUrl);
            case "social_security_card":
                return recognizeSocialSecurityCardByUrl(imageUrl);
            case "household_register":
                return recognizeHouseholdRegisterByUrl(imageUrl);
            case "marriage_certificate":
                return recognizeMarriageCertificateByUrl(imageUrl);
            case "property_certificate":
                return recognizePropertyCertificateByUrl(imageUrl);
            case "birth_certificate":
                return recognizeBirthCertificateByUrl(imageUrl);
            case "degree_certificate":
                return recognizeDegreeCertificateByUrl(imageUrl);
            case "graduation_certificate":
                return recognizeGraduationCertificateByUrl(imageUrl);
            default:
                // 未知证件类型，返回错误
                return AjaxResult.error("不支持的证件类型: " + certType);
        }
    }

    @Override
    public AjaxResult recognizeCertificate(String imageBase64, String certType, boolean truncateForDoc) {
        // 如果图片数据为空，返回错误信息
        if (StringUtils.isEmpty(imageBase64)) {
            return AjaxResult.error("图片数据不能为空");
        }
        
        // 如果未指定证件类型，则默认为身份证
        if (StringUtils.isEmpty(certType)) {
            certType = "id_card";
        }

        log.info("调用统一证件识别接口(带截断标志)，证件类型: {}, 截断标志: {}", certType, truncateForDoc);
        
        // 直接调用不带截断标志的方法，因为现在已经不支持截断功能
        return recognizeCertificate(imageBase64, certType);
    }
    
    @Override
    public AjaxResult recognizeCertificateByUrl(String imageUrl, String certType, boolean truncateForDoc) {
        // 如果URL为空，返回错误信息
        if (StringUtils.isEmpty(imageUrl)) {
            return AjaxResult.error("图片URL不能为空");
        }
        
        // 如果未指定证件类型，则默认为身份证
        if (StringUtils.isEmpty(certType)) {
            certType = "id_card";
        }

        log.info("调用统一证件识别接口(带截断标志)，证件类型: {}, 截断标志: {}", certType, truncateForDoc);
        
        // 直接调用不带截断标志的方法，因为现在已经不支持截断功能
        return recognizeCertificateByUrl(imageUrl, certType);
    }

    /**
     * 从缓存获取结果，如果未找到或已过期则返回null
     * 
     * @param cacheKey 缓存键
     * @return 缓存的结果或null
     */
    private String getFromCache(String cacheKey) {
        String cachedResult = TextInCacheUtils.getFromCache(RECOGNITION_CACHE, cacheKey);
        if (cachedResult != null) {
            log.info("缓存命中，使用缓存结果，键: {}", cacheKey);
        }
        return cachedResult;
    }
    
    /**
     * 将结果存入缓存
     * 
     * @param cacheKey 缓存键
     * @param result 识别结果
     */
    private void putIntoCache(String cacheKey, String result) {
        // 缓存大小检查，如果超出最大限制，清理一部分旧条目
        if (RECOGNITION_CACHE.size() >= TextInConstants.MAX_CACHE_SIZE) {
            log.info("缓存达到最大大小({}条)，清理过期条目", TextInConstants.MAX_CACHE_SIZE);
            // 清理过期条目
            cleanupExpiredCache();
            
            // 如果清理后仍然接近限制，移除最早的20%条目
            if (RECOGNITION_CACHE.size() >= TextInConstants.MAX_CACHE_SIZE * 0.9) {
                log.info("缓存接近限制，移除一部分旧条目");
                List<String> keys = new ArrayList<>(RECOGNITION_CACHE.keySet());
                
                // 这里我们不能直接访问CacheEntry的timestamp字段
                // 所以改用缓存工具类的方法来处理
                TextInCacheUtils.cleanExpiredEntries(RECOGNITION_CACHE);
                
                // 如果清理后仍然太多，简单地删除一些最早的条目
                if (RECOGNITION_CACHE.size() >= TextInConstants.MAX_CACHE_SIZE * 0.8) {
                    int removeCount = Math.max(1, RECOGNITION_CACHE.size() / 5);
                    int i = 0;
                    for (String key : keys) {
                        if (i >= removeCount) break;
                        RECOGNITION_CACHE.remove(key);
                        i++;
                    }
                }
            }
        }
        
        // 添加新条目到缓存
        TextInCacheUtils.putIntoCache(RECOGNITION_CACHE, cacheKey, result);
        log.info("结果已缓存，缓存键: {}", cacheKey);
    }
    
    /**
     * 清理过期的缓存条目
     * 
     * @return 已清理的条目数量
     */
    private static int cleanupExpiredCache() {
        int sizeBefore = RECOGNITION_CACHE.size();
        TextInCacheUtils.cleanExpiredEntries(RECOGNITION_CACHE);
        int sizeAfter = RECOGNITION_CACHE.size();
        return sizeBefore - sizeAfter;
    }
    
    /**
     * 计算图片数据的哈希值，用作缓存键
     * 
     * @param imageData 图片二进制数据
     * @param apiUrl API URL（不同API服务的结果不同）
     * @return 哈希值
     */
    private String calculateImageHash(byte[] imageData, String apiUrl) {
        try {
            // 组合图片数据和API URL生成哈希
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            md.update(imageData);
            md.update(apiUrl.getBytes());
            
            byte[] digest = md.digest();
            StringBuilder sb = new StringBuilder();
            for (byte b : digest) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        } catch (Exception e) {
            log.warn("计算图片哈希值失败，将不使用缓存: {}", e.getMessage());
            // 如果计算哈希失败，使用随机值确保不会命中缓存
            return UUID.randomUUID().toString();
        }
    }
    
    /**
     * 计算URL图片的哈希值，用作缓存键
     * 
     * @param imageUrl 图片URL
     * @param apiUrl API URL
     * @return 哈希值
     */
    private String calculateUrlHash(String imageUrl, String apiUrl) {
        try {
            // 组合图片URL和API URL生成哈希
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            md.update(imageUrl.getBytes());
            md.update(apiUrl.getBytes());
            
            byte[] digest = md.digest();
            StringBuilder sb = new StringBuilder();
            for (byte b : digest) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        } catch (Exception e) {
            log.warn("计算URL哈希值失败，将不使用缓存: {}", e.getMessage());
            // 如果计算哈希失败，使用随机值确保不会命中缓存
            return UUID.randomUUID().toString();
        }
    }
    
    /**
     * 请求Textin API (使用URL)
     * 添加缓存优化
     */
    private String requestTextinApiWithUrl(String imageUrl, String apiUrl) throws IOException {
        // 计算缓存键
        String cacheKey = TextInCacheUtils.calculateUrlHash(imageUrl, apiUrl.substring(apiUrl.lastIndexOf("/") + 1));
        
        // 查询缓存
        String cachedResult = TextInCacheUtils.getFromCache(RECOGNITION_CACHE, cacheKey);
        if (cachedResult != null) {
            return cachedResult;
        }
        
        // 获取API凭证
        String appId = textInProperties.getAppId();
        String secretCode = textInProperties.getSecretCode();
        
        if (StringUtils.isEmpty(appId) || StringUtils.isEmpty(secretCode)) {
            throw new RuntimeException("API凭证不完整，请检查配置");
        }
        
        log.info("使用URL方式请求Textin API: " + apiUrl);
        log.info("图片URL: " + imageUrl);
        
        BufferedReader in = null;
        DataOutputStream out = null;
        StringBuilder result = new StringBuilder();
        
        try {
            URL url = new URL(apiUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            // 设置超时
            conn.setConnectTimeout(TextInConstants.CONNECTION_TIMEOUT);
            conn.setReadTimeout(TextInConstants.READ_TIMEOUT);
            // 设置请求头
            conn.setRequestProperty("Content-Type", "text/plain");
            conn.setRequestProperty("x-ti-app-id", appId);
            conn.setRequestProperty("x-ti-secret-code", secretCode);
            
            // 设置请求方法
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setRequestMethod("POST");
            
            // 发送请求数据 - 直接发送URL文本
            out = new DataOutputStream(conn.getOutputStream());
            out.write(imageUrl.getBytes("UTF-8"));
            out.flush();
            
            // 获取响应码
            int responseCode = conn.getResponseCode();
            log.info("API响应码: " + responseCode);
            
            // 读取响应
            if (responseCode == HttpURLConnection.HTTP_OK) {
                in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
            } else {
                log.error("API请求失败，状态码: " + responseCode);
                in = new BufferedReader(new InputStreamReader(conn.getErrorStream(), "UTF-8"));
            }
            
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
            
            // 不在日志中输出大量响应数据
            log.info("API响应已接收，长度: " + result.length() + " 字符");
            
            // 将结果存入缓存（只缓存成功的结果）
            String resultString = result.toString();
            
            // 判断是否为成功的响应再加入缓存
            JSONObject resultObj = JSON.parseObject(resultString);
            if (resultObj.containsKey("code") && resultObj.getIntValue("code") == 200) {
                TextInCacheUtils.putIntoCache(RECOGNITION_CACHE, cacheKey, resultString);
            }
            
            return resultString;
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    log.error("关闭输出流出错", e);
                }
            }
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    log.error("关闭输入流出错", e);
                }
            }
        }
    }

    /**
     * 请求Textin API (使用二进制数据)
     * 添加缓存优化
     */
    private String requestTextinApi(byte[] requestData, boolean needEncryption, String apiUrl) throws IOException {
        // 计算缓存键
        String cacheKey = TextInCacheUtils.calculateImageHash(
            Base64.getEncoder().encodeToString(requestData),
            apiUrl.substring(apiUrl.lastIndexOf("/") + 1));
        
        // 查询缓存
        String cachedResult = TextInCacheUtils.getFromCache(RECOGNITION_CACHE, cacheKey);
        if (cachedResult != null) {
            return cachedResult;
        }
        
        // 获取API凭证
        String appId = textInProperties.getAppId();
        String secretCode = textInProperties.getSecretCode();
        
        if (StringUtils.isEmpty(appId) || StringUtils.isEmpty(secretCode)) {
            throw new RuntimeException("API凭证不完整，请检查配置");
        }
        
        log.info("请求Textin API: " + apiUrl);
        log.info("数据大小: " + requestData.length + " 字节");
        
        BufferedReader in = null;
        DataOutputStream out = null;
        StringBuilder result = new StringBuilder();
        
        try {
            URL url = new URL(apiUrl);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            // 设置超时
            conn.setConnectTimeout(TextInConstants.CONNECTION_TIMEOUT);
            conn.setReadTimeout(TextInConstants.READ_TIMEOUT);
            // 设置请求头，不要设置Content-Length，HttpURLConnection会自动设置
            conn.setRequestProperty("Content-Type", "application/octet-stream");
            conn.setRequestProperty("x-ti-app-id", appId);
            conn.setRequestProperty("x-ti-secret-code", secretCode);
            
            // 设置请求方法
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setRequestMethod("POST");
            
            // 发送请求数据
            out = new DataOutputStream(conn.getOutputStream());
            out.write(requestData);
            out.flush();
            
            // 获取响应码
            int responseCode = conn.getResponseCode();
            log.info("API响应码: " + responseCode);
            
            // 读取响应
            if (responseCode == HttpURLConnection.HTTP_OK) {
                in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));
            } else {
                log.error("API请求失败，状态码: " + responseCode + ", 响应信息: " + conn.getResponseMessage());
                in = new BufferedReader(new InputStreamReader(conn.getErrorStream(), "UTF-8"));
            }
            
            String line;
            while ((line = in.readLine()) != null) {
                result.append(line);
            }
            
            // 不在日志中输出大量响应数据
            log.info("API响应已接收，长度: " + result.length() + " 字符");
            
            // 将结果存入缓存（只缓存成功的结果）
            String resultString = result.toString();
            
            // 判断是否为成功的响应再加入缓存
            JSONObject resultObj = JSON.parseObject(resultString);
            if (resultObj.containsKey("code") && resultObj.getIntValue("code") == 200) {
                TextInCacheUtils.putIntoCache(RECOGNITION_CACHE, cacheKey, resultString);
            }
            
            return resultString;
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    log.error("关闭输出流出错", e);
                }
            }
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    log.error("关闭输入流出错", e);
                }
            }
        }
    }
} 